#pragma once
#include<vector>
#include<mutex>
#include<condition_variable>

template<typename T>
class CycleBlockingQueue {
private:
	std::vector<T>buffer;
	int size;
	int front = { 0 };
	int rear = { 0 };

	std::mutex mx;
	std::condition_variable p_cond;
	std::condition_variable c_cond;

	bool isEmpty() {
		return front == rear;
	}
	bool isFull() {
		return (rear + 1) % size == front;
	}

public:
	CycleBlockingQueue(int bs) :
		buffer(bs + 1), size(bs + 1) {

	}

	void push(T& val) {
		std::unique_lock<std::mutex> lock(mx);
		p_cond.wait(lock, [&]() {return !isFull(); });
		buffer[rear] = val;
		rear = (rear + 1) % size;
		c_cond.notify_one();
	}

	T pop() {
		std::unique_lock<std::mutex> lock(mx);
		c_cond.wait(lock, [&]() {return !isEmpty(); });
		T val = buffer[front];
		front = (front + 1) % size;
		p_cond.notify_one();
		return val;
	}
};